home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 054 (1988-05-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 054 (1988-05-15)(Ossowski, Stefan)(DE)(PD).adf / MRBackup / MRBackup2.0 / FormatDisk.c < prev    next >
C/C++ Source or Header  |  1988-04-09  |  10KB  |  374 lines

  1. /* Format a floppy disk (880k drive).
  2.  * Author:        Mark R. Rinfret
  3.  * Date:        06/28/87
  4.  * Description:
  5.  *        This set of routines may be incorporated into a program which
  6.  *    has need of formatting a floppy disk.  I wrote it to support my
  7.  *    hard disk backup utility.
  8.  *
  9.  * History:        (most recent change first)
  10.  *
  11.  * 12/08/87 -MRR- My floppy drive (at least) will occaisionally "hang"
  12.  *                during formatting.  I don't know what the source of
  13.  *                the problem is, but for now I've added a timer and
  14.  *                switched to a SendIO/Wait combo to handle this.
  15.  *
  16.  * 08/26/87 -MRR- Modified FormatDisk to delay 5 seconds after
  17.  *                  uninhibiting the drive.  This should give enough time
  18.  *                for the validator to do its thing and prevent the
  19.  *                  "Insert disk..." requester from rearing its ugly head
  20.  *                if the application attempts to access the disk as
  21.  *                soon as we return.
  22.  */
  23.  
  24. #include <exec/types.h>
  25. #include <exec/memory.h>
  26. #include <exec/io.h>
  27. #include <exec/devices.h>
  28. #include <devices/trackdisk.h>
  29. #include <libraries/dosextens.h>
  30. #include ":src/lib/AmigaFunctions.h"
  31.  
  32. #include ":src/lib/Timer.h"
  33.  
  34. extern struct IOExtTD *CreateExtIO();
  35.  
  36. static int CkIOErr();
  37.  
  38. #define MAX_NAME    30L
  39. #define TD_WRITE    CMD_WRITE
  40. #define TRACKSIZE    NUMSECS * TD_SECTOR
  41.  
  42.  
  43. /* Format a floppy disk - hardwired for the 3.5" 880k floppy drives.
  44.  * Called with:
  45.  *        drivename:    device name (DF0, etc.)
  46.  *      name:        new volume name
  47.  * Returns:
  48.  *        Zero on success, 1 on failure
  49.  * Note:
  50.  *        This routine does not currently perform a verification, as
  51.  *        recommended by the RKM.  Perhaps later...
  52.  *        I also discovered that there's some erroneous crap in 
  53.  *        "The Amiga Programmer's Workbook, Vol. II", by 
  54.  *        Eugene P. Mortimore.  On page 339, he states that only 512
  55.  *        bytes of track data are required for formatting.  The RKM
  56.  *        correctly states that a "track's worth of data" is required.
  57.  *        It took some playing with DiskEd to discover this error.
  58.  */
  59.  
  60. int 
  61. FormatDisk(drivename,name)
  62.     char *drivename; char *name;
  63. {
  64.     long checkSum;
  65.     char *dosID = "DOS";
  66.     long dosWord = 0;
  67.     short error;
  68.     long diskBit, timerBit;
  69.     struct MsgPort *diskPort = NULL;
  70.     struct IOExtTD *diskRequest = NULL;
  71.     ULONG diskChangeCount;
  72.     USHORT retries, status = 0, i, timeout, track;
  73.     long signals;                        /* signal bits from Wait() */
  74.     struct timerequest *timeRequest;        /* timeout timer request */
  75.     int unit; 
  76.     char *volname;
  77.  
  78.     char *diskBuffer;
  79.     ULONG *diskBlock;            /* alias for diskBuffer, ULONG type */
  80.  
  81.     if (strlen(name) >= MAX_NAME) {
  82. #ifdef DEBUG
  83.         printf("Disk name is too long!\n");
  84. #endif
  85.         status = ERROR_INVALID_COMPONENT_NAME;    
  86.         goto cleanup;
  87.     }
  88.  
  89.     if ((unit = (drivename[2]-'0')) < 0 || unit >= NUMUNITS) {
  90. #ifdef DEBUG
  91.         printf("FormatDisk: invalid drive specification!\n");
  92. #endif
  93.         status = ERROR_INVALID_COMPONENT_NAME;
  94.         goto cleanup;
  95.     }
  96.  
  97.     if (!(diskBuffer = 
  98.         AllocMem((long) TRACKSIZE, MEMF_PUBLIC | MEMF_CHIP))) {
  99.         status = ERROR_NO_FREE_STORE;
  100.         goto cleanup;
  101.     }
  102.  
  103.     timeRequest = CreateTimer(0);    /* create uHERZ timer */
  104.     if (timeRequest == NULL) {
  105.         status = ERROR_NO_FREE_STORE;    /* would IoError be valid? */
  106.         goto cleanup;
  107.     }
  108.  
  109.     /* Store DOS "magic word" in disk block to be written during
  110.      * formatting. 
  111.      */
  112.     diskBlock = (ULONG *) diskBuffer;/* we'll need this later */
  113.     for (i = 0; i < 3; ++i)
  114.         dosWord = (dosWord << 8) | dosID[i];
  115.     dosWord = dosWord << 8;
  116.  
  117. #ifdef DEBUG
  118.     printf("dosWord is %lx\n",dosWord);
  119. #endif
  120.     for (i = 0; i < TRACKSIZE / 4; ++i)
  121.         diskBlock[i] = (dosWord | (long) (i & 0xff));
  122.  
  123.     if ((diskPort = CreatePort(0L, 0L)) == NULL) {
  124. #ifdef DEBUG
  125.         printf("FormatDisk can't create port!\n");
  126. #endif
  127.         status = 1;                        /* is there a better error code? */
  128.         goto cleanup;
  129.     }
  130.  
  131.     if (!(diskRequest = (struct IOExtTD *) 
  132.         CreateExtIO(diskPort, (long) sizeof(struct IOExtTD)))) {
  133.         status = 1;
  134.         goto cleanup;
  135.     }
  136.  
  137.     if (status = OpenDevice(TD_NAME, (long) unit, diskRequest, 0L)) {
  138. #ifdef DEBUG
  139.         printf("FormatDisk: OpenDevice error: %d\n",error);
  140. #endif
  141.         goto cleanup;
  142.     }
  143.  
  144.     if (status = Inhibit(drivename, 1)) {
  145. #ifdef DEBUG
  146.         printf("FormatDisk: unable to inhibit drive!\n");
  147. #endif
  148.         goto cleanup;
  149.     }
  150.  
  151. /* Get the current disk change count.  This allows the trackdisk
  152.  * driver to detect unwanted disk changes later on.
  153.  */
  154.  
  155.     diskRequest->iotd_Req.io_Command = TD_CHANGENUM;
  156.     DoIO(diskRequest);
  157.  
  158. /* Save a copy of the disk change count. */
  159.  
  160.     diskChangeCount = diskRequest->iotd_Req.io_Actual;
  161.  
  162. #ifdef DEBUG
  163.     printf("Current disk change count is %ld\n", diskChangeCount);
  164. #endif
  165.  
  166.  
  167.     /* Format the disk, one track at a time.  This operation seems
  168.      * susceptible to timing out (infrequently) on my system, so we'll
  169.      * use a combination of SendIO and Wait, rather than DoIO.
  170.      */
  171.  
  172.     diskBit = 
  173.         1L << diskRequest->iotd_Req.io_Message.mn_ReplyPort->mp_SigBit;
  174.     timerBit =     
  175.         1L << timeRequest->tr_node.io_Message.mn_ReplyPort->mp_SigBit;
  176.  
  177. #ifdef DEBUG
  178.     printf("diskBit => %08lx,  timerBit => %08lx\n",
  179.             diskBit, timerBit);
  180. #endif
  181.  
  182.     for (track = 0; track < NUMTRACKS; ++track) {
  183.         retries = 0;
  184. retry:
  185.         diskRequest->iotd_Req.io_Command = TD_FORMAT;
  186.         diskRequest->iotd_Req.io_Flags = 0;
  187.         diskRequest->iotd_Req.io_Data = (APTR) diskBuffer;
  188.         diskRequest->iotd_Count = diskChangeCount;
  189.         diskRequest->iotd_Req.io_Length = NUMSECS * TD_SECTOR; 
  190.         diskRequest->iotd_Req.io_Offset = track * NUMSECS * TD_SECTOR;
  191.         SendIO(diskRequest);
  192.  
  193.         StartTimer(timeRequest, 5L, 0L); /* Start 5 second disk timer. */
  194. #ifdef DEBUG
  195.         if (timeRequest->tr_node.io_Error) {
  196.             printf("Error on StartTimer: %d\n",
  197.                     timeRequest->tr_node.io_Error);
  198.         }
  199. #endif
  200.         while (TRUE) {
  201.             timeout = 0;
  202.             signals = Wait(diskBit | timerBit);
  203.             if (signals & timerBit) {
  204.                 if (CheckIO(timeRequest)) {    /* timer I/O complete? */
  205.                     WaitIO(timeRequest);    /* complete timer processing */
  206.                     AbortIO(diskRequest);    /* kill disk I/O */
  207.                     timeout = 1;
  208. #ifdef DEBUG
  209.                     puts("--TIMEOUT--");
  210. #endif
  211.                     break;
  212.                 }
  213.             }
  214.  
  215.             if (signals & diskBit) {    /* Did disk complete? */
  216.                 if (CheckIO(diskRequest)) {
  217.                     WaitIO(diskRequest); /* complete disk processing */
  218.                     StopTimer(timeRequest);
  219.                     break;
  220.                 }
  221.             }
  222.         }                            /* end while(TRUE) */
  223.  
  224.         /* Retry a timeout 3 times before giving up. */
  225.  
  226.         if (timeout && (++retries < 4) ) goto retry;
  227.  
  228.         if (status = CkIOErr(diskRequest,"Formatting error")) {
  229. #ifdef DEBUG
  230.             printf("  Track: %d\n",track);
  231. #endif
  232.             goto cleanup;
  233.         }
  234.     }
  235.  
  236.     /* Now comes some real KLUDGING.  Fill in the root block and the
  237.      * first hash block.  The information for this was gathered from
  238.      * the "AmigaDos Technical Reference Manual" and some sleuthing
  239.      * with DiskEd.
  240.      */
  241.  
  242.     for (i = 0; i < 128; ++i)
  243.         diskBlock[i] = 0;
  244.  
  245.     diskBlock[0] = 2;            /* T.SHORT (type) */
  246.     diskBlock[3] = 128 - 56;    /* hashtable size */
  247.     diskBlock[78] = 0xffffffff; /* BMFLAG */
  248.     diskBlock[79] = 881;        /* first bitmap block */
  249.     DateStamp(&diskBlock[105]);    /* volume last altered date/time */
  250.     DateStamp(&diskBlock[121]); /* volume creation date/time */
  251.     volname = (char *) &diskBlock[108];
  252.     /* convert input name to BSTR */
  253.     *volname = strlen(name);
  254.     for (i = 0; i < *volname; ++i)
  255.         *(volname + 1 + i) = *(name + i);
  256.  
  257.     diskBlock[127] = 1;            /* ST.ROOT (secondary type) */
  258.  
  259.     checkSum = 0;
  260.     for (i = 0; i < 128; ++i)
  261.         checkSum += diskBlock[i];
  262.  
  263.     diskBlock[5] = - checkSum;
  264.  
  265.     /* Write the root block out to the disk. */
  266.  
  267.     diskRequest->iotd_Req.io_Command = TD_WRITE;
  268.     diskRequest->iotd_Req.io_Length = TD_SECTOR;
  269.     diskRequest->iotd_Req.io_Offset = TD_SECTOR * 880L;
  270.     DoIO(diskRequest);
  271.     if (status = CkIOErr(diskRequest, "Error writing root block")) {
  272.         goto cleanup;
  273.     }
  274.  
  275.     /* Write the first bitmap block. */
  276.  
  277.     for (i = 0; i < 56; ++i)
  278.         diskBlock[i] = 0xffffffff;
  279.  
  280.     for (i = 56; i < 128; ++i)
  281.         diskBlock[i] = 0;
  282.  
  283.     diskBlock[0] = 0xc000c037;    /* hint: x37 = 55 (last word of map?) */
  284.     diskBlock[28] = 0xffff3fff; /* blocks 880, 881 used */
  285.     diskBlock[55] = 0x3fffffff; /* blocks 1760, 1761 used? */
  286.  
  287.     diskRequest->iotd_Req.io_Length = TD_SECTOR;
  288.     diskRequest->iotd_Req.io_Offset = 881L * TD_SECTOR;
  289.     DoIO(diskRequest);                    /* write out the bitmap */
  290.     if (status = CkIOErr(diskRequest, "Error writing bitmap")) {
  291.         goto cleanup;
  292.     }
  293.  
  294.     diskRequest->iotd_Req.io_Command = ETD_UPDATE;
  295.     diskRequest->iotd_Req.io_Flags = 0;
  296.     DoIO(diskRequest);
  297.  
  298.     /* Turn the disk motor off. */
  299.  
  300.     diskRequest->iotd_Req.io_Command = TD_MOTOR;
  301.     diskRequest->iotd_Req.io_Length = 0;
  302.     DoIO(diskRequest);
  303.     Inhibit(drivename, 0);                /* enable disk validator */
  304.  
  305.     Delay(3L * TICKS_PER_SECOND);        /* Give it a chance */
  306.  
  307. cleanup:
  308.     CloseDevice(diskRequest);
  309.     if (diskBuffer) FreeMem(diskBuffer, (long) TRACKSIZE);
  310.     if (diskRequest) DeleteExtIO(diskRequest, (long) sizeof(*diskRequest));
  311.     if (diskPort) DeletePort(diskPort);
  312.     if (timeRequest) DeleteTimer(timeRequest);
  313.     return status;
  314. }
  315.  
  316. /* Check the disk request block for an error code.  If an error
  317.  * occurred, print the argument string.
  318.  * Called with:
  319.  *        req:    pointer to I/O request structure
  320.  *        msg:    error message string
  321.  * Returns:
  322.  *        error code from request structure
  323.  */
  324. static int CkIOErr(req, msg)
  325.     struct IOStdReq *req; char *msg;
  326. {
  327.     register int code;
  328.  
  329.     if (code = req->io_Error) {
  330. #ifdef DEBUG
  331.         printf("%s, code: %d\n",msg,code);
  332. #endif
  333.     }
  334.     return code;
  335. }
  336.  
  337. #ifdef DEBUG
  338. main(argc, argv)
  339.     int argc; char *argv[];
  340. {
  341.     char *diskname;
  342.     char *volname;
  343.  
  344.     int unit;
  345.  
  346.     if (argc < 3)
  347.         volname = "GoodJob!";
  348.     else
  349.         volname = argv[2];
  350.  
  351.     if (argc < 2)
  352.         diskname = "DF1:";
  353.     else {
  354.         diskname = argv[1];
  355.         if (strlen(diskname) != 4 || 
  356.             (strncmp(diskname,"df",2) && strncmp(diskname,"DF",2))) {
  357. bad_drive:
  358.             printf("Drive name may only be df0: through df3:!\n");
  359.             exit(1);
  360.         }
  361.         if ((unit = (diskname[2] - '0')) < 0 || unit > 3)
  362.             goto bad_drive;
  363.  
  364.     }
  365.     printf("Insert disk in %s, then hit return\n",diskname);
  366.     while (getchar() != '\n');
  367.     if (FormatDisk(diskname,volname))
  368.         printf("FormatDisk failed\n");
  369.     else {
  370.         printf("FormatDisk succeeded\n");
  371.     }
  372. }
  373. #endif
  374.